//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<thread.h>
///	@path	~/src/lib/system/
///	@date	2007/09/10
///	@desc	Thread encapsulation.

#pragma once

#include "xeres.h"

#include <vector>

#include "lib/utilities/time.h"

namespace xeres {

	/*!
		\class	Thread
		\brief	Encapsulate a usual thread.

		\sa	ThreadLock
	*/
	class Thread
	{
	public:

		/// \name Constructor & Destructor
		//@{

		/// \ctor
		Thread( void );

		/// \dtor
		virtual ~Thread( void );

		//@}

		/// \name Thread Manipulation
		//@{

		/*!
			\brief		Create a thread, but suspends.
		*/
		void Create( void );

		/*!
			\brief		Start thread to run.
		*/
		void Start( void );

		/*!
			\brief		Query if thread is running.
			\return		Thread running status.
		*/
		bool IsRunning( void ) const;

		/*!
			\brief		Wait until the thread ends.
		*/
		void Wait( void );

		/*!
			\brief		Wait the thread ends in time.
			\return		True if thread stops in time.
			\param[in]	time	Wait time.
		*/
		bool Wait( const Time& time );

		/// \brief Thread priority.
		enum Priority
		{
			/// \brief Real time priority, be careful to use.
			PRIORITY_REALTIME		= 15,
			/// \brief Thread runs above normal, higher priority.
			PRIORITY_ABOVR_NORMAL	= 1,
			/// \brief Normal priority.
			PRIORITY_NORMAL			= 0 ,
			/// \brief Lower priority, suitable for background worker.
			PRIORITY_BELOW_NORMAL	= -1 ,
			/// \brief Idle priority.
			PRIORITY_IDLE			= -15,
		};

		/*!
			\brief		Set thread running priority.
			\param[in]	priority	Priority of thread,
									should be a value of enumeration above.
		*/
		void SetPriority( Priority priority );

		/*!
			\brief		Get thread current user time.
			\return		User time of thread.
		*/
		Time GetUserTime( void ) const;

		/*!
			\brief		Get thread current kernel time.
			\return		Kernel time of thread.
		*/
		Time GetKernelTime( void ) const;

		/*!
			\brief		Set single processor affinity.
		*/
		void SingleAffinity( int no_processor );

		/*!
			\brief		Set multiple processor affinity.
		*/
		void MultiAffinity( const std::vector<bool>& affinity );

		/*! 
			\brief		Set thread name.
		*/
		void SetThreadName( const AString& name );

		/*! 
			\brief		Get thread name.
		*/
		const char * GetThreadName( void );

		/*!
			\brief		Get current thread pointer,
						will return NULL if current thread is user-created.
		*/
		static Thread * GetCurrent( void );

		/*!
			\brief		Initialize main thread.
						This function should be called before any other call of 'Thread',
						and should be called in main thread.
		*/
		static void InitMain( void );

		//@}
		
		/// \name Thread Interface
		//@{

		/*!
			\brief		Execution of a thread.
			\return		Thread exit code.
		*/
		virtual uint32 Execute( void ) = 0;

		//@}

	protected:

		/*!
			\brief		Get thread handle.
			\return		Current thread handle.
		*/
		uintptr_t Handle( void ) const { return m_thread; }

	private:

		// Thread execution wrap.
		static uint32 __stdcall Run( void * data );

		// handle of thread
		uintptr_t		m_thread;
	};

	/*!
		\class	ProcThread
		\brief	A simple thread runs specific procedure.
		\details
			A procedure thread is a thread that runs a simple procedure.
			The procedure only contains one parameter, & returns immediately
			when jobs are finished.
	*/
	class ProcThread : public Thread
	{
	public:

		/// \ctor_set
		ProcThread( function<void(void)> proc );

		/// \brief Executes procedure
		virtual uint32 Execute( void );

	private:

		// data
		function<void(void)>	m_proc;
	};


} // namespace xeres
